{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# KNN Classifier\n",
    "\n",
    "In KNN Classification, there are only two steps. \n",
    "\n",
    "1. Find k nearest neighbors\n",
    "2. Calculate y based on the k nearest neighbors\n",
    "\n",
    "Hence the name KNN.\n",
    "\n",
    "For step two, y is the most frequent value for classification, mean value for reguression.\n",
    "\n",
    "The following example illustrates this algorithm:\n",
    "\n",
    "![knn](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/KnnClassification.svg/330px-KnnClassification.svg.png)\n",
    "\n",
    "the green round point is what we are going to predict. If k is 3 for KNN, the neighbors are two red triangles and one blue square. The most frequent neighbor is the red triangle. Thus, the green round point is predicted a red triangle."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Automatically created module for IPython interactive environment\n"
     ]
    }
   ],
   "source": [
    "print(__doc__)\n",
    "import math\n",
    "from collections import Counter \n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.colors import ListedColormap\n",
    "# Create color maps\n",
    "cmap_light = ListedColormap(['orange', 'cyan', 'cornflowerblue'])\n",
    "cmap_bold = ListedColormap(['darkorange', 'c', 'darkblue'])\n",
    "from sklearn import neighbors, datasets\n",
    "\n",
    "n_neighbors = 15\n",
    "\n",
    "# import some data to play with\n",
    "iris = datasets.load_iris()\n",
    "\n",
    "# we only take the first two features. We could avoid this ugly\n",
    "# slicing by using a two-dim dataset\n",
    "X = iris.data[:, :2]\n",
    "y = iris.target"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following is the KNNClassifier class. We see it is very simple and straight-forward. We have only three methods. The first is fit. It just take X and y and remember it without doing any calculation. It is a **lazy** algorithm. It starts to calculate in the prediction phase. In the prediction phase, it firstly find the $neighbors$ of the point $p$, the the labels of the neighbors, at last the most frequent value is calculated based on the $neighbor\\_labels$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [],
   "source": [
    "class KNNClassifier():\n",
    "    X=None\n",
    "    y=None\n",
    "    n_neighbors=0\n",
    "    \n",
    "    def __init__(self, n_neighbors=15):\n",
    "        self.n_neighbors=n_neighbors\n",
    "        \n",
    "    def fit(self, X, y):\n",
    "        self.X=np.array(X)\n",
    "        self.y=np.array(y)\n",
    "    \n",
    "    def predict_one(self, p):\n",
    "        distance_array=np.array(list(map(lambda o: math.dist(p, o), self.X)))\n",
    "        argsorted=np.argsort(distance_array)\n",
    "        neighbours = argsorted[:self.n_neighbors]\n",
    "        neighbour_labels = y[neighbours]\n",
    "        occurence_count = Counter(neighbour_labels)\n",
    "        most_frequent = occurence_count.most_common(1)[0][0]\n",
    "        return most_frequent\n",
    "        \n",
    "    def predict(self, X):\n",
    "        y_hat = np.array(list(map(self.predict_one, X)))\n",
    "        return y_hat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "knn = KNNClassifier()\n",
    "knn.fit(X, y)\n",
    "\n",
    "x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1\n",
    "y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1\n",
    "h = .02  # step size in the mesh\n",
    "xx, yy = np.meshgrid(np.arange(x_min, x_max, h),\n",
    "                     np.arange(y_min, y_max, h))\n",
    "Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])\n",
    "\n",
    "# Put the result into a color plot\n",
    "Z = Z.reshape(xx.shape)\n",
    "plt.figure()\n",
    "plt.pcolormesh(xx, yy, Z, cmap=cmap_light)\n",
    "\n",
    "# Plot also the training points\n",
    "plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,\n",
    "            edgecolor='k', s=20)\n",
    "plt.xlim(xx.min(), xx.max())\n",
    "plt.ylim(yy.min(), yy.max())\n",
    "plt.title(\"My KNN (k = %i)\"\n",
    "          % (n_neighbors))\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Compare with Scikit-learn\n",
    "\n",
    "Here we compare our implementation with the one in Scikit-learn. We see that there are almost the same."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# we create an instance of Neighbours Classifier and fit the data.\n",
    "clf = neighbors.KNeighborsClassifier(n_neighbors)\n",
    "clf.fit(X, y)\n",
    "\n",
    "# Plot the decision boundary. For that, we will assign a color to each\n",
    "# point in the mesh [x_min, x_max]x[y_min, y_max].\n",
    "x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1\n",
    "y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1\n",
    "h = .02  # step size in the mesh\n",
    "xx, yy = np.meshgrid(np.arange(x_min, x_max, h),\n",
    "                     np.arange(y_min, y_max, h))\n",
    "Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])\n",
    "\n",
    "# Put the result into a color plot\n",
    "Z = Z.reshape(xx.shape)\n",
    "plt.pcolormesh(xx, yy, Z, cmap=cmap_light)\n",
    "\n",
    "# Plot also the training points\n",
    "plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,\n",
    "            edgecolor='k', s=20)\n",
    "plt.xlim(xx.min(), xx.max())\n",
    "plt.ylim(yy.min(), yy.max())\n",
    "plt.title(\"Scikit-learn KNN (k = %i)\"\n",
    "          % (n_neighbors))\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Reference\n",
    "https://scikit-learn.org/stable/auto_examples/neighbors/plot_classification.html#sphx-glr-auto-examples-neighbors-plot-classification-py\n",
    "\n",
    "https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
